#include "Bsp_Uart.h"
#include "Ext_StrPrint.h"

#if USE_USART1
    COM_TypeDef COM1;
    static uint8_t Uart1_RxBuf[USART1_RxBUF_SIZE]  = {0, };
    static uint8_t Uart1_TxBuf[USART1_TxBUF_SIZE]  = {0, };
#endif

#if USE_USART2
    COM_TypeDef COM2;
    static uint8_t Uart2_RxBuf[USART2_RxBUF_SIZE]  = {0, };
    static uint8_t Uart2_TxBuf[USART2_TxBUF_SIZE]  = {0, };
#endif

static void Uart_Rx_Callback(COM_TypeDef *COMx);
static void Uart_Tx_Callback(COM_TypeDef *COMx);

void BSP_UART_Init(COM_TypeDef *COMx)
{
    COMx->Uart_Rx_Cnt         = 0;
    COMx->Uart_RxTimeOut      = 0;
    COMx->Uart_Tx_Read_Idx    = 0;
    COMx->Uart_Tx_Write_Idx   = 0;
    COMx->Uart_Tx_Busy        = 0;

#if USE_USART1
    if (COMx == &COM1)
    {
        COMx->UARTx      = UART1;
        COMx->Uart_RxBuf = Uart1_RxBuf;
        COMx->Uart_TxBuf = Uart1_TxBuf;
        COMx->Uart_RxBuf_Size = USART1_RxBUF_SIZE;
        COMx->Uart_TxBuf_Size = USART1_TxBUF_SIZE;

        SCON  = 0x50;   // 8位数据,可变波特率
        AUXR |= 0x40;   // 定时器1时钟为Fosc,即1T
        AUXR &= 0xFE;   // 串口1选择定时器1为波特率发生器
        TMOD &= 0x0F;   // 设定定时器1为16位自动重装方式

        TL1  = (65536 - FOSC / USART1_BAUD / 4) & 0xFF;
        TH1  = (65536 - FOSC / USART1_BAUD / 4) >> 8;
        ET1 = 0;		// 禁止定时器1中断
        TR1 = 1;

        ES  = 1;    // 使能中断
    }
#endif

#if USE_USART2
    if (COMx == &COM2)
    {
        COMx->UARTx      = UART2;
        COMx->Uart_RxBuf = Uart2_RxBuf;
        COMx->Uart_TxBuf = Uart2_TxBuf;
        COMx->Uart_RxBuf_Size = USART2_RxBUF_SIZE;
        COMx->Uart_TxBuf_Size = USART2_TxBUF_SIZE;

        S2CON  = 0x50;  // 8位数据,可变波特率
        AUXR  |= T2x12; // 时钟不分频,定时器2时钟为Fosc,即1T

        T2L  = (65536 - FOSC / USART2_BAUD / 4) & 0xFF;
        T2H  = (65536 - FOSC / USART2_BAUD / 4) >> 8;
        AUXR  |= T2R;   // 启动定时器2

        S2CON |= ES2;   // 使能中断
    }
#endif
}

uint16_t BSP_UART_GetTxFreeSize(COM_TypeDef *COMx)
{
    uint16_t ret = 0;

    if (COMx->Uart_Tx_Write_Idx >= COMx->Uart_Tx_Read_Idx)
    {
        ret = COMx->Uart_TxBuf_Size - (COMx->Uart_Tx_Write_Idx - COMx->Uart_Tx_Read_Idx);
    }
    else
    {
        ret = COMx->Uart_Tx_Read_Idx - COMx->Uart_Tx_Write_Idx;
    }

    return ret; // 返回Tx剩余空间大小
}

uint16_t BSP_UART_SendBuff(COM_TypeDef *COMx, uint8_t *Data, uint16_t Data_Len)
{
    uint16_t i;

    i = BSP_UART_GetTxFreeSize(COMx);
    if (i < Data_Len)
    {
        return 0;   // 剩余空间不够，发送失败
    }
    
    // 写入缓存
    for (i = 0; i < Data_Len; i++)
    {
        COMx->Uart_TxBuf[COMx->Uart_Tx_Write_Idx ++] = Data[i];
        
        if (COMx->Uart_Tx_Write_Idx >= COMx->Uart_TxBuf_Size)
        {
            COMx->Uart_Tx_Write_Idx = 0;
        }
    }

    // 忙标志
    COMx->Uart_Tx_Busy = 1;

    return 1;
}

uint8_t BSP_UART_GetTxBusy(COM_TypeDef *COMx)
{
    return COMx->Uart_Tx_Busy;
}

void BSP_UART_RxStart(COM_TypeDef *COMx)
{
    // 清除标志
    COMx->Uart_Rx_Cnt = 0;
}

void BSP_UART_TxStart(COM_TypeDef *COMx)
{
    // 触发中断
    switch (COMx->UARTx)
    {
    case UART1:
        TI = 1;
        break;
    
    case UART2:
        S2CON |= S2TI;
        break;
    
    default:
        break;
    }
}

static void Uart_Rx_Callback(COM_TypeDef *COMx)
{
    if (COMx->Uart_Rx_Cnt < COMx->Uart_RxBuf_Size)
    {
        switch (COMx->UARTx)
        {
        case UART1:
            COMx->Uart_RxBuf[COMx->Uart_Rx_Cnt] = SBUF;
            break;
        
        case UART2:
            COMx->Uart_RxBuf[COMx->Uart_Rx_Cnt] = S2BUF;
            break;
        
        default:
            break;
        }

        // 数据缓存位置
        COMx->Uart_Rx_Cnt ++;
    }

    // 祯空闲间隔
    COMx->Uart_RxTimeOut = 3;    // 1000 / 9600 * 10位 * 1字符 = 1.04ms
}

static void Uart_Tx_Callback(COM_TypeDef *COMx)
{
    if (COMx->Uart_Tx_Read_Idx != COMx->Uart_Tx_Write_Idx)
    {
        // 发送
        switch (COMx->UARTx)
        {
        case UART1:
            SBUF = COMx->Uart_TxBuf[COMx->Uart_Tx_Read_Idx ++];
            break;
        
        case UART2:
            S2BUF = COMx->Uart_TxBuf[COMx->Uart_Tx_Read_Idx ++];
            break;
        
        default:
            break;
        }

        if (COMx->Uart_Tx_Read_Idx >= COMx->Uart_TxBuf_Size)
        {
            COMx->Uart_Tx_Read_Idx = 0;
        }
    }
    else
    {
        // 发送完成
        COMx->Uart_Tx_Busy = 0;
    }
}

/***********************  串口中断  **************************/
#if USE_USART1
void USART1_IRQHandler(void) interrupt 4
{
    if (RI)
    {
        RI = 0;
        
        Uart_Rx_Callback(&COM1);
    }

    if(TI)
    {
        TI = 0;

        Uart_Tx_Callback(&COM1);
    }
}
#endif

#if USE_USART2
void USART2_IRQHandler(void) interrupt 8
{
    if (S2CON & S2RI)
    {
        S2CON ^= S2RI;

        Uart_Rx_Callback(&COM2);
    }

    if (S2CON & S2TI)
    {
        S2CON ^= S2TI;
        
        Uart_Tx_Callback(&COM2);
    }
}
#endif

/*************************  串口打印  *****************************/
uint8_t BSP_UART_Printf(COM_TypeDef *COMx, const char *Str, ...)
{
    char Buf[USART_PRINTF_BUF_SIZE];
    uint8_t DataLen = 0;

    va_list ap;
    va_start(ap, Str);
    
    DataLen = String_format(Buf, Str, ap);
    BSP_UART_SendBuff(COMx, (uint8_t *)&Buf, DataLen);

    va_end(ap);

    return DataLen;
}
